package simplytypeddebruijn

/**
   * adapted from parser for untyped lambda calculus by Miles Sabin 
   */

trait AbstractSyntax  { self : AbstractSyntax => 

 type VarRef = Int
 type VarHint = String
 
 

   sealed trait LTerm 

trait BaseValue extends LTerm {
  def baseType():BaseType
}


 case class Tru extends LTerm with BaseValue{
   override def toString = "true"
   override def baseType = TyBool
 }
 case class Fls extends LTerm with BaseValue{
   override def toString= "false"
   override def baseType = TyBool
 }
 case class Unit extends LTerm with BaseValue{
   override def toString = "unit"
   override def baseType = TyUnit
 }
 case class Lit(n: int) extends LTerm with BaseValue{
   override def toString = n.toString
   override def baseType = TyInt
 }
 
 
 case class If(cond: LTerm, pos: LTerm, neg: LTerm) extends LTerm {

 }

 
 

 case class Var(n: VarRef) extends LTerm  {
 }
 
 case class Lam(hint: VarHint, ty: LType, body: LTerm) extends LTerm {
 }
 
 case class App(funt:LTerm, argt:LTerm) extends LTerm {
 }
 case class Let(n: VarHint, t1: LTerm, t2: LTerm) extends LTerm {
   override def toString = "let "+n+" = "+t1+" in "+t2
 }
 
 
 case class Record(fields: List[(String,LTerm)]) extends LTerm {
   override def toString = "{" + fields.foldRight("")({case ((s,t),xs) => s +"="+ t +", "+ xs} )+ "}"
   def fieldsmap[R](f:LTerm=>R):List[(String,R)] =
     fields.map({case (label,fld)=> (label,f(fld))})
 }
 case class RecProj(t: LTerm, label: String) extends LTerm {
   
 }



 sealed trait LType extends LTerm 
 
 trait BaseType extends LType {
   val name: String
   override def toString = name
 }
 
 case class TyBool() extends LType with BaseType
 { val name="Bool" }
 case class TyInt()  extends LType with BaseType
 { val name="Int"  }
 case class TyTop()  extends LType with BaseType
 { val name="Top"  }
 case class TyUnit() extends LType with BaseType
 { val name="Unit" }

 case class TyArr(fundom: LType, funrange: LType) extends LType {
   override def toString = "("+fundom +" => " +funrange+")"
   def map(f:LType=>LType):TyArr=
      TyArr(f(fundom), f(funrange))
 }


 case class TyRecord(fields: List[(String,LType)]) extends LType {
   def map[R](f:LType=>R):List[(String,R)] =
       fields.map({case (label,fld)=> (label,f(fld))})
   def field(label:String) = {
       val results = fields.filter( {case (fldlabel,fldtype) => label == fldlabel}).map(_ _2)
       if (results.length == 0)throw new TypeExc("no label "+label+" in record")
       if (results.length >1  )throw new TypeExc("multiple labels "+label+" in record")
       results.head
   }
 }
 
 


}
 

